#include "Material.h"

namespace Nezha
{

	Material::Material(const _string& name)
		//:mHandle(0)
		:mName(name)
	{

	}

	Material::~Material()
	{
		for(PassArray::iterator it = mPasses.begin(); it != mPasses.end(); it++)
		{
			NZ_Delete (*it);
		}
	}

	const RenderPass* Material::getPass(u32 i) const
	{
		NZ_ASSERT(i < mPasses.size());

		return mPasses[i];
	}

	RenderPass* Material::_getPass(u32 i)
	{
		NZ_ASSERT(i < mPasses.size());

		return mPasses[i];
	}

	const RenderPass* Material::getPass(const _string& name) const
	{
		for(PassArray::const_iterator it = mPasses.begin(); it != mPasses.end(); it++)
		{
			if((*it)->getName() == name)
			{
				return (*it);
			}
		}

		return NULL;
	}

	RenderPass* Material::_getPass(const _string& name)
	{
		for(PassArray::iterator it = mPasses.begin(); it != mPasses.end(); it++)
		{
			if((*it)->getName() == name)
			{
				return (*it);
			}
		}

		return NULL;
	}

	const RS_Blending& Material::getBlendingState(u32 passIndex) const
	{
		NZ_ASSERT(passIndex < mPasses.size());

		RenderPass* p = mPasses[passIndex];
		return p->mBlending;
	}

	const RS_Depth& Material::getDepthState(u32 passIndex) const
	{
		NZ_ASSERT(passIndex < mPasses.size());

		RenderPass* p = mPasses[passIndex];
		return p->mDepth;
	}

	const RS_PolygonOffset& Material::getOffsetState(u32 passIndex) const
	{
		NZ_ASSERT(passIndex < mPasses.size());

		RenderPass* p = mPasses[passIndex];
		return p->mOffset;
	}

	const RS_Stencil& Material::getStencilState(u32 passIndex) const
	{
		NZ_ASSERT(passIndex < mPasses.size());

		RenderPass* p = mPasses[passIndex];
		return p->mStencil;
	}

	const RS_CullOrder& Material::getCullState(u32 passIndex) const
	{
		NZ_ASSERT(passIndex < mPasses.size());

		RenderPass* p = mPasses[passIndex];
		return p->mCull;
	}

	const RS_FillMode& Material::getFillMode(u32 passIndex) const
	{
		NZ_ASSERT(passIndex < mPasses.size());

		RenderPass* p = mPasses[passIndex];
		return p->mFillMode;
	}

	_SamplerInfo Material::getSampler(u32 passIndex, u32 i) const
	{
		NZ_ASSERT(passIndex < mPasses.size());
		NZ_ASSERT(i < RenderPass::GetMaxSamplersPerPass());

		RenderPass* p = mPasses[passIndex];

		NZ_ASSERT(i < p->getNumSamplers());

		return p->getSamper(i)->getSamplerInfo();
	}

	void Material::setCullOrder(u32 passIndex, RS_CullOrder co)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mCull = co;
	}

	void Material::setBlend(u32 passIndex, bool b)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mBlending.mBlendingEnable = b;
	}

	void Material::setBlendSrc(u32 passIndex, BlendFactor src)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mBlending.mSrc = src;
	}

	void Material::setBlendDst(u32 passIndex, BlendFactor dst)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mBlending.mDst = dst;
	}

	void Material::setBlendFactor(u32 passIndex, BlendFactor src, BlendFactor dst)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mBlending.mSrc = src;
		mPasses[passIndex]->mBlending.mDst = dst;
	}

	void Material::setAlphaTestFunc(u32 passIndex, RS_CmpMode cmp)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mBlending.mCmpMode = cmp;
	}

	void Material::setAlphaTestRef(u32 passIndex, float reference)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mBlending.mReference = reference;
	}

	void Material::setBlendConstColor(u32 passIndex, const RGBA& rgba)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mBlending.mConstantColor = rgba;
	}

	void Material::setDepth(u32 passIndex, bool b)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mDepth.mEnabled = b;
	}

	void Material::setDepthWrite(u32 passIndex, bool b)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mDepth.mWritable = b;
	}

	void Material::setDepthCmp(u32 passIndex, RS_CmpMode cmp)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mDepth.mCmpMode = cmp;
	}

	void Material::setStencil(u32 passIndex, bool b)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mStencil.mEnabled = b;
	}

	void Material::setStencilFunc(u32 passIndex, RS_CmpMode cmp)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mStencil.mCmpMode = cmp;
	}

	void Material::setStencilRef(u32 passIndex, u32 uRef)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mStencil.mReference = uRef;
	}

	void Material::setStencilMask(u32 passIndex, u32 mask)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mStencil.mMask = mask;
	}

	void Material::setStencilWMask(u32 passIndex, u32 writeMask)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mStencil.mWriteMask = writeMask;
	}

	void Material::setStencilOPFail(u32 passIndex, RS_StencilOP op)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mStencil.mOnFail = op;
	}

	void Material::setStencilOPZFail(u32 passIndex, RS_StencilOP op)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mStencil.mOnZFail = op;
	}

	void Material::setStencilOPPass(u32 passIndex, RS_StencilOP op)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mStencil.mOnPass = op;
	}

	void Material::setFillMode(u32 passIndex, const RS_FillMode& fm)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mFillMode = fm;
	}

	void Material::setPolygonOffset(u32 passIndex, bool enable)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mOffset.mFillEnabled = enable;
	}

	void Material::setDepthBias(u32 passIndex, float scale, float bias)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		mPasses[passIndex]->mOffset.mScale = scale;
		mPasses[passIndex]->mOffset.mBias = bias;
	}

	ShaderParameter* Material::getUserSpecParam(u32 passIndex, const _string& name)
	{
		NZ_ASSERT(passIndex < mPasses.size());

		RenderPass* rp = mPasses[passIndex];
		u32 numParams = rp->getNumParams();
		ShaderParameter* sp = NULL;

		for(u32 i = 0; i < numParams; i++)
		{
			sp = rp->getParam(i);
			if(sp->getCategory() == SPC_APP && sp->getName() == name)
			{
				return sp;
			}
		}

		return NULL;
	}

	bool Material::hasIllumPass() const
	{
		for(PassArray::const_iterator it = mPasses.begin(); it != mPasses.end(); it++)
		{
			if((*it)->hasIlluminationParam())
			{
				return true;
			}
		}

		return false;
	}

	RenderPass* Material::createPass(const _string& name, const ShaderProgramPtr& sp)
	{
		RenderPass* rp = _getPass(name);

		if(rp)
		{
			return rp;
		}

		rp = NZ_New RenderPass(name);
		mPasses.push_back(rp);

		if(sp.ptr())
			rp->setProgram(sp);

		return rp;
	}

	RenderPass* Material::createPass(const RenderPass* rpTemplate)
	{
		RenderPass* rp = _getPass(rpTemplate->getName());

		if(rp)
		{
			return rp;
		}

		rp = NZ_New RenderPass(rpTemplate->getName());
		mPasses.push_back(rp);

		if(rpTemplate->getProgram())
			rp->setProgram(rpTemplate->getProgramPtr());

		rp->copyRenderStatesFrom(rpTemplate);

		return rp;
	}

}//end namespace Nezha